package com.corecmd.tcloud.tcimserver.service.impl;

import com.corecmd.tcloud.tcimcommon.im.common.PacketCodeC;
import com.corecmd.tcloud.tcimcommon.im.domain.MessageRequestPacket;
import com.corecmd.tcloud.tcimserver.domain.ImChatSessionDTO;
import com.corecmd.tcloud.tcimserver.domain.ImFriendDTO;
import com.corecmd.tcloud.tcimserver.domain.ImMessageDO;
import com.corecmd.tcloud.tcimserver.domain.UserInfoDTO;
import com.corecmd.tcloud.tcimserver.enums.*;
import com.corecmd.tcloud.tcimserver.im.common.ImSessionHolder;
import com.corecmd.tcloud.tcimserver.mapper.IChatMessageMapper;
import com.corecmd.tcloud.tcimserver.mapper.IChatSessionMapper;
import com.corecmd.tcloud.tcimserver.service.IChatSessionService;
import com.corecmd.tcloud.tcimserver.service.IFriendService;
import com.corecmd.tcloud.tcimserver.service.IUserService;
import com.corecmd.tcloud.tcimserver.service.SendMessageToClientsService;
import com.corecmd.tcloud.tcimserver.utils.CustomResponse;
import com.corecmd.tcloud.tcimserver.utils.UniqueId;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.corecmd.tcloud.tcimcommon.im.common.MessageType.*;

/**
 * @author : TianShaoJiao
 * @date : 2021/2/22
 * @description :
 **/
@Slf4j
@Service
public class SendMessageToClientsServiceImpl implements SendMessageToClientsService {

    @Autowired
    private IFriendService friendService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IChatMessageMapper chatMessageMapper;
    @Autowired
    private IChatSessionService chatSessionService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public CustomResponse sendMessage(MessageRequestPacket messagePacket) throws Exception{
        CustomResponse customResponse = null;
        String messageType = messagePacket.getMsgType();
        switch (messageType){
            case SYS_KICK_OUT_NOTIFY:
            case SHAKE_YOU_NOTIFY:
            case SYS_CLIENT:
            case SINGLE_CHAT:
                //将消息发送给接收人
                customResponse = sendMsgToReceiver(messagePacket);
                break;
            case ONLINE_NOTIFY:
            case OFFLINE_NOTIFY:
                //将消息发送给发送人的好友
                customResponse = sendMsgToFriends(messagePacket);
                break;
            case GROUP_CHAT:
                //将消息发送给接收人id对应的群组成员
                customResponse = sendMsgToGroup(messagePacket);
                break;
            case SYS_NOTIFY:
                //将消息发送给所有客户端
                customResponse = sendMsgToAllClient(messagePacket);
                break;
        }
        if (customResponse == null){
            customResponse = CustomResponse.error("推送消息失败,解析消息类型："+messageType+"失败");
        }
        return customResponse;
    }
    /**
     * 将消息发送给所有客户端
     * @param messagePacket 消息包
     * @return 是否推送成功
     * @throws Exception 推送异常
     */
    private CustomResponse sendMsgToAllClient(MessageRequestPacket messagePacket) throws Exception{
        ImSessionHolder.broadcastMessage(messagePacket);
        return CustomResponse.ok("推送成功");
    }
    /**
     * 将消息发送给群组
     * @param messagePacket 消息包
     * @return 是否推送成功
     * @throws Exception 推送异常
     */
    private CustomResponse sendMsgToGroup(MessageRequestPacket messagePacket) throws Exception{
        return null;
    }
    /**
     * 将消息发送给好友
     * @param messagePacket 消息包
     * @return 是否推送成功
     * @throws Exception 推送异常
     */
    private CustomResponse sendMsgToFriends(MessageRequestPacket messagePacket) throws Exception{
        return null;
    }

    /**
     * 将消息发送给接收人
     * @param messagePacket 消息包
     * @return 是否推送成功
     * @throws Exception 推送异常
     */
    private CustomResponse sendMsgToReceiver(MessageRequestPacket messagePacket) throws Exception{
        CustomResponse response = null;
        //单聊时，需要保持聊天记录
        if (messagePacket.getMsgType().charAt(0) == MessageTypeEnum.SINGLE_CHAT.getTypeEn()){
            response = saveSingleChat(messagePacket);
        }
        //推送消息到客户端
        NioSocketChannel clientChannel = ImSessionHolder.get(String.valueOf(messagePacket.getReceiverId()));
        if (null != clientChannel){
            log.info("推送消息到客户端:"+clientChannel.attr(AttributeKey.valueOf("userName")));
            // 编码
            ByteBuf buffer = new PacketCodeC().encode(messagePacket);
            // 写数据
            ChannelFuture future = clientChannel.writeAndFlush(buffer);
            future.sync();
            if (!future.isSuccess()){
                log.info("消息推送失败，原因："+future.cause());
            }
        } else {
            log.info("本机推送好友添加请求消息失败，无客户端：{}连接信息",messagePacket.getReceiverId());
        }
        if (null == response){
            response = CustomResponse.ok("消息推送成功");
        }
        return response;
    }

    private CustomResponse saveSingleChat(MessageRequestPacket messagePacket) throws Exception{
        int receiverId = Integer.parseInt(messagePacket.getReceiverId());
        int senderId = Integer.parseInt(messagePacket.getSenderId());
        UserInfoDTO senderInfo = userService.getUser(senderId);
        if (senderInfo == null){
            return CustomResponse.error("消息发送人："+senderId+"不存在，消息推送失败");
        }
        UserInfoDTO receiverInFo = userService.getUser(Integer.parseInt(messagePacket.getReceiverId()));
        if (receiverInFo == null){
            return CustomResponse.error("消息发送人："+receiverId+"不存在，消息推送失败");
        }
        //判断接收人是否添加了发送人为好友
        Map<String,Object> query = new HashMap<>(1);
        query.put("friendId",senderId);
        List<ImFriendDTO> friendInfos = friendService.getFriends(receiverInFo,query);
        if (null == friendInfos || friendInfos.size() <= 0){
            return CustomResponse.error("对方还不是您的好友，发送消息失败");
        }
        ImFriendDTO friendDTO = friendInfos.get(0);
        if (friendDTO.getRelationStatus() == FriendRelationStatusEnum.BLACKLIST.getTypeEn()){
            return CustomResponse.error("对方已将您屏蔽，消息发送失败");
        }
        ImMessageDO newMessage = new ImMessageDO();
        newMessage.setContentType(messagePacket.getMsgContentType().charAt(0));
        newMessage.setMessageType(messagePacket.getMsgType().charAt(0));
        newMessage.setSenderId(Integer.parseInt(messagePacket.getSenderId()));
        newMessage.setReceiverId(Integer.parseInt(messagePacket.getReceiverId()));
        newMessage.setCreateTime(new Date());
        newMessage.setStatus(AvailableStatusEnum.YES.getCode());
        newMessage.setMsgContent(messagePacket.getMsgContent());
        //保存消息到消息发送人
        ImChatSessionDTO senderSession = getImChatSession(senderInfo,receiverId);
        newMessage.setId(UniqueId.getUniqueId());
        newMessage.setReadFlag(AvailableStatusEnum.YES.getCode());
        newMessage.setChatSessionId(senderSession.getId());
        chatMessageMapper.save(newMessage);
        //保存消息到消息接收人
        ImChatSessionDTO receiverSession = getImChatSession(receiverInFo,senderId);
        newMessage.setId(UniqueId.getUniqueId());
        newMessage.setReadFlag(AvailableStatusEnum.NO.getCode());
        newMessage.setChatSessionId(receiverSession.getId());
        chatMessageMapper.save(newMessage);
        return CustomResponse.ok("消息推送成功");
    }

    /**
     * 取得聊天会话，没有就新建
     * @param userInfo
     * @param receiverId
     * @return
     */
    private ImChatSessionDTO getImChatSession(UserInfoDTO userInfo, int receiverId) {
        ImChatSessionDTO imChatSessionDTO = null;
        Map<String,Object> query = new HashMap<>();
        query.put("receiverId",receiverId);
        List<ImChatSessionDTO> chatSessions = chatSessionService.getSessions(userInfo,query);
        if (null != chatSessions && chatSessions.size() > 0){
            imChatSessionDTO = chatSessions.get(0);
        } else {
            //新建会话
            imChatSessionDTO = chatSessionService.createChatSession(userInfo,String.valueOf(receiverId), String.valueOf(ImChatSessionTypeEnum.SINGLE_CHAT.getTypeEn()));
        }
        return imChatSessionDTO;
    }
}
